package com.ae.shield.common.capability.Itemhandler;

import net.minecraft.item.ItemStack;
import net.minecraft.nbt.CompoundNBT;
import net.minecraft.nbt.INBT;
import net.minecraft.nbt.ListNBT;
import net.minecraft.util.NonNullList;
import net.minecraftforge.common.util.Constants;
import net.minecraftforge.items.ItemHandlerHelper;
import net.minecraftforge.items.ItemStackHandler;

import javax.annotation.Nonnull;

public class ModItemStackHandler extends ItemStackHandler {
    private final ItemStack stack;
    private final int size;

    public ModItemStackHandler(int size, ItemStack stack) {
        super(size);
        this.stack = stack;
        this.size = size;
        deserializeNBT(new CompoundNBT());
    }

    @Nonnull
    @Override
    public ItemStack insertItem(int slot, @Nonnull ItemStack stack, boolean simulate) {
        if (stack.isEmpty())
            return ItemStack.EMPTY;

        if (!isItemValid(slot, stack))
            return stack;

        validateSlotIndex(slot);

        ItemStack existing = this.stacks.get(slot);

        int limit = getStackLimit(slot, stack);

        if (!existing.isEmpty()) {
            if (!ItemHandlerHelper.canItemStacksStack(stack, existing))
                return stack;

            limit -= existing.getCount();
        }

        if (limit <= 0)
            return stack;

        boolean reachedLimit = stack.getCount() > limit;

        if (!simulate) {
            if (existing.isEmpty()) {
                this.stacks.set(slot, reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, limit) : stack);
            } else {
                existing.grow(reachedLimit ? limit : stack.getCount());
            }
            onContentsChanged(slot);
        }

        return reachedLimit ? ItemHandlerHelper.copyStackWithSize(stack, stack.getCount() - limit) : ItemStack.EMPTY;
    }

    @Nonnull
    @Override
    public ItemStack extractItem(int slot, int amount, boolean simulate) {
        if (amount == 0)
            return ItemStack.EMPTY;

        validateSlotIndex(slot);

        ItemStack existing = this.stacks.get(slot);

        if (existing.isEmpty())
            return ItemStack.EMPTY;

        int toExtract = Math.min(amount, existing.getMaxStackSize());

        if (existing.getCount() <= toExtract) {
            if (!simulate) {
                this.stacks.set(slot, ItemStack.EMPTY);
                onContentsChanged(slot);
                return existing;
            } else {
                return existing.copy();
            }
        } else {
            if (!simulate) {
                this.stacks.set(slot, ItemHandlerHelper.copyStackWithSize(existing, existing.getCount() - toExtract));
                onContentsChanged(slot);
            }

            return ItemHandlerHelper.copyStackWithSize(existing, toExtract);
        }
    }

    @Override
    public CompoundNBT serializeNBT() {
        ListNBT nbtTagList = new ListNBT();
        for (ItemStack stack : stacks) {
            nbtTagList.add(stack.serializeNBT());
        }

        setItemsTag(nbtTagList);
        return new CompoundNBT();
    }

    @Override
    public void deserializeNBT(CompoundNBT nbt) {
        ListNBT nbtTagList = getItemsTag();
        for (int i = 0; i < nbtTagList.size(); i++) {
            CompoundNBT itemTag = nbtTagList.getCompound(i);
            stacks.set(i, ItemStack.read(itemTag));
        }

        onLoad();
    }

    @Override
    protected void onContentsChanged(int slot) {
        ListNBT itemsTag = getItemsTag();
        itemsTag.set(slot, stacks.get(slot).serializeNBT());
        setItemsTag(itemsTag);
    }

    private ListNBT getItemsTag() {
        ListNBT items = stack.getOrCreateTag().getList("Items", Constants.NBT.TAG_COMPOUND);
        if (items.isEmpty()) {
            ListNBT listNBT = new ListNBT();
            for (int i = 0; i < size; i++) {
                listNBT.add(ItemStack.EMPTY.serializeNBT());
            }
            items = listNBT;
        }
        return items;
    }

    private void setItemsTag(INBT nbt) {
        stack.getOrCreateTag().put("Items", nbt);
    }

    public NonNullList<ItemStack> getInv() {
        return stacks;
    }

}
